#ifndef CHESS_HPP
#	define CHESS_HPP

class Position;

#	include <iostream>
#	include <list>
#	include <map>

using namespace std;

struct LoadActions;
class Piece;
class PawnPromotionAction;
class CastlingAction;
class Action;
class Chessboard;
class Player;
struct ChessGameState;
class Chess;



struct CastlingState
{
	bool	king_side;
	bool	queen_side;
	bool	castlingPossible()
	{	return (king_side || queen_side);	}
	
};

class Chess
{
	public:
		
		typedef enum { WHITE = 0 , BLACK } Color;
		typedef enum { WAITING_FOR_ACTION = 0, WAITING_FOR_PAWN_PROMOTION, GAME_OVER } EngineState;
		typedef enum { NONE = 0 , STALEMATE, CHECKMATE_IMPOSSIBLE } DrawState;
		typedef enum { STANDARD = 0, CHECK, CHECKMATE } PlayerState;
		typedef enum { ILLEGAL_MOVE = 0, PAWN_PROMOTION_REQUIRED, ILLEGAL_PAWN_PROMOTION, GAME_IS_OVER, NO_ERROR } ExecError;
		
		struct	GameState
		{
			unsigned int				cgs_turn;		// current turn number
			Chess::Color				cgs_player;		// current player
			Chess::PlayerState			cgs_pstate;		// current player's state
			Chess::DrawState			cgs_dstate;		// game draw state
			Chess::EngineState			cgs_estate;		// main engine state
			Chessboard*					cgs_cboard;		// current_chessboard
			list<Action*>				cgs_lmoves;		// list of legal actions availables
			Piece*						cgs_ppawn;		// pawn to promote
		};
		
		static Chess* 			getInstance();	
		
		~Chess();
		
		static Chess::Color 	oppositeColor(Chess::Color color);
		void					init();
		void 					reset();
		Chess::ExecError 		execute(Action* action);
		Chess::GameState		getState() const;
		Chessboard*				getChessboard() const;
		Player&					getPlayer(Chess::Color);
		void 					save(string filename);
		void					load(string filename);
				
		
		
	private:
		
		static Chess* 			instance;
		Chess();
		
		bool					checkCheckForPlayer(Chess::Color c);
		list<Action*>			getLegalMovesForPlayer(Chess::Color c);
		void 					calcState(bool changeturn = true);
		bool 					executePawnPromotion(Action* action);
		bool 					executeAction(Action* action);
		void					playActions(LoadActions* loadactions);
		
		
		Chessboard*				chessboard;
		Player*					players[Chess::BLACK + 1];
		Chess::GameState		state;
};





#endif
